<?php
declare(strict_types=1);

namespace app\index\controller\api;

use lib\ExtiStorage;
use \Swoole\Http\Request;
use \Swoole\Http\Response;
use sys\Log;

class Goods
{
    public \lib\User $user;
    public \lib\Merchant $merchant;
    public $middleware = [
        \lib\middleware\NetbarAuth::class=>[]
    ];

    # 读取网吧商品列表
    public function read(Request $request, Response $response)
    {
        $post = json_decode($request->getContent(), true);
        $validate = validate([
            'page' => 'require|number',
            'limit' => 'require|number',
            'cat_id' => 'number',
        ], __FILE__.'.'.__LINE__)->check($post);
        if(!$validate->pass()) return $validate->jsonSerialize();
        
        $db = new \sys\Db();
        $total = $data = $db->table('tp_nb_goods_rack')->where([['tp_nb_goods_rack.mid','=',$this->user->mid]])->count('id');
        $data = $db->table('tp_nb_goods_rack,tp_nb_goods')
            ->join('tp_nb_goods', 'tp_nb_goods.id = tp_nb_goods_rack.goods_id','LEFT JOIN')
            ->where([['tp_nb_goods_rack.mid','=',$this->user->mid]])
            ->field([
                'tp_nb_goods_rack.id',
                'tp_nb_goods_rack.goods_id',
                'tp_nb_goods_rack.category_ids',
                'tp_nb_goods_rack.sale_price',
                'COALESCE(tp_nb_goods.suggest_price, 0) AS suggest_price',
                'COALESCE(tp_nb_goods.num_sale, 0) AS num_sale',
                'COALESCE(tp_nb_goods.allow_ol, 1) AS allow_ol',
                'tp_nb_goods_rack.prop',
                'tp_nb_goods_rack.allow_mb',
                'COALESCE(tp_nb_goods.on_sale, 1) AS on_sale',
                'COALESCE(tp_nb_goods_rack.name, tp_nb_goods.name) AS name',
                'COALESCE(tp_nb_goods_rack.img, tp_nb_goods.img) AS img',
                'COALESCE(tp_nb_goods_rack.code, tp_nb_goods.code) AS code',
                'COALESCE(tp_nb_goods_rack.spec, tp_nb_goods.spec, \'\') AS spec',
            ])
            ->page($post['page'], $post['limit'])
            ->select();
        return [
            'success'=>true,
            'data'=>[
                'total'=>$total,
                'data'=>$data
            ]
        ];
    }

    public function save(Request $request, Response $response) {
        $post = json_decode($request->getContent(), true);
        $check = validate([
            'id'            => 'uinteger',
            'goods_id'      => 'uinteger',          # 未绑定到商品目录时传0
            'code'          => 'requireIf:id',      # 添加的时候,未绑定到商品目录时传空. 修改的时候传原来的.
            'name'          => 'require|length:1,64',
            'prop'          => 'require|unumber:between:0,2',
            'pack_size'     => 'require|uinteger|between:1,9999',
            'sale_price'    => 'require|number|between:0,999999.99',
            'category_ids'  => 'require|intlist:1',
            'inside'        => 'require|boolean',   # 是否是店内码
        ], __FILE__.'.'.__LINE__)->check($post);
        if(!$check->pass()) return $check->jsonSerialize();
        $post['mid'] = $mid = $this->merchant->id;
        
        # 全部强行转换成 int
        $post['category_ids'] = array_map(function($v){return (int)$v;}, $post['category_ids']);

        # 是否选择默认分类判断
        if(null !== ($def = \lib\data\Category::getDefaultCategory($mid))){
            if(!in_array($def->id, $post['category_ids'])){
                return [
                    'success'=>false,
                    'message'=>'必须选择默认分类'
                ];
            }
        }

        # 分类有效性判断
        $realCatNum = 0;
        foreach($post['category_ids'] as $cat_id){
            if(null === ($cat = \lib\data\Category::get($cat_id)) || $cat->mid != $mid){
                return [
                    'success'=>false,
                    'message'=>'分类不存在'
                ];
            }
            # 默认分类跳过
            if($cat->def) continue;

            # 商品分类只允许加一个 虚拟分类不受限制.
            if($cat->prop == 1) $realCatNum ++;
        }

        if($post['prop'] != \lib\data\Components::PROP_MATERIAL && $realCatNum !== 1){
            return [
                'success'=>false,
                'message'=>$realCatNum ==0 ? '商品必须加入一个"真实"商品分类' : '商品只能加入一个"真实"商品分类',
            ];
        }

        $mid = $this->merchant->id;

        Log::console("goods save start {$mid}", 'DEBUG');
        if(isset($post['id'])){
            if(null === ($goods = \lib\data\Components::get((int)$post['id'])) || $goods->mid != $mid){
                return [
                    'success'=>false,
                    'message'=>'商品不存在'
                ];
            }

            $goods->waitLock();

            $oldImg = $goods->img;

            if(null !==($changed = $goods->update([
                'name'          => $post['name'],
                'img'           => $post['img'],
                'spec'          => $post['spec'],
                'sale_price'    => (float)$post['sale_price'],
                'pack_size'     => (int)$post['pack_size'],
                'category_ids'  => $post['category_ids'],
            ]))){
                if($oldImg !== $post['img']) {
                    if(null !== ($meta = \lib\ExtiStorage::getmeta($oldImg))){
                        if($meta['mid'] === $mid && $meta['goods_id'] === $goods->id){
                            \lib\ExtiStorage::delete($oldImg);
                        }
                    }
                }

                if(!empty($post['img'])){
                    \lib\ExtiStorage::setmeta($post['img'], ['mid'=>$mid, 'goods_id'=>$goods->id,'expire'=>-1]);
                }

                $db = new \sys\db();
                $db->table('tp_nb_goods_rack')->where(['id','=', $goods->id])->update($changed);
                $syncObject = new \lib\sync\Synchronize($mid, $db);
                $syncObject->up('Goods', $goods->id, $changed);
                return ['success'=>true, 'message'=>'修改成功.', 'data'=>$goods];
            }
            return ['success'=>false, 'message'=>'未做任何修改.'];
        }else{
            $time = time();
            $db = new \sys\Db();
            $db->startTrans();
            try{
                # 生成店内码
                $sortId = $db->table('tp_nb_goods_rack')->where([['mid','=', $mid]])->field(['COALESCE(MAX(`sortid`)+1,1) AS `sortid`'])->find()['sortid'];
                if($post['inside']){
                    $post['goods_id'] = 0;
                    $icode = $db->table('tp_nb_goods_rack')->where([['mid','=', $mid], ['code','EXP', 'LENGTH(`code`)=10']])->field(['COALESCE(MAX(`code`)+1,1) AS `code`'])->find()['code'];
                    $post['code']  = str_pad($icode, 10, '0', STR_PAD_LEFT);
                    $post['suggest_price'] = 0;
                    $post['on_sale']    = true;
                    $post['allow_ol']   = true;
                    $needKeepPhoto      = true;
                } else {
                    ## 添加到商品库. 
                    if(isEAN13($post['code'])){
                        $dict = $this->attachToGoodsDict($db, $post);
                        if(null !== ($raw = \lib\data\Components::getByGoodsId($mid, $dict['id']))){
                            return ['success'=>false, 'message'=>'商品已经存在, 请勿重复添加.'];
                        }

                        # 从商品字典钟补充数据
                        $post['goods_id'] = $dict['id'];
                        $post['suggest_price'] = $dict['suggest_price'];
                        $post['on_sale'] = $dict['on_sale'];
                        $post['allow_ol']   = $dict['allow_ol'];

                        if(empty($post['img'])){
                            $post['img'] = $dict['img'];
                            $needKeepPhoto = false;
                        }elseif($post['img'] == $dict['img']){
                            $needKeepPhoto = false;
                        }else{
                            $needKeepPhoto = true;
                        }
                        
                    }else{
                        $db->rollback();
                        return ['success'=>false, 'message'=>'商品条码不正确.'];
                    }
                }
                unset($post['inside']);
                $data = [
                    'mid'           => $mid,
                    'code'          => $post['code'],
                    'name'          => $post['name'],
                    'spec'          => $post['spec'] ?? '',
                    'img'           => $post['img'] ?? '',
                    'goods_id'      => $post['goods_id'],
                    'category_ids'  => $post['category_ids'],
                    'sale_price'    => (float)$post['sale_price'],
                    'prop'          => $post['prop'],
                    'pack_size'     => (int)$post['pack_size'],
                    'receipt'       => true,
                    'createtime'    => $time,
                    'updatetime'    => $time,
                    'allow_mb'      => true,
                    'num_sale'      => 0,
                    'pack_price'    => 0,
                    'piece_price'   => 0,
                    'num'           => 0,
                    'sortid'        => (int)$sortId,
                ];
                $data['id'] = $db->table('tp_nb_goods_rack')->insert($data);
                $db->commit();

                # 保持照片不再删除
                if(!empty($data['img']) && $needKeepPhoto){
                    \lib\ExtiStorage::setmeta($data['img'], ['mid'=>$mid, 'goods_id'=>$data['id'],'expire'=>-1]);
                }

                $data = array_merge($data,[
                    'suggest_price' => $post['suggest_price'],
                    'on_sale'       => $post['on_sale'],
                    'allow_ol'      => $post['allow_ol'],
                ]);
                $goods = new \lib\data\Components($data);
                $syncObject = new \lib\sync\Synchronize($mid, $db);
                $syncObject->put('Goods', $goods);
                return ['success'=>true, 'message'=>'添加成功.', 'data'=>$goods];
            }catch(\Exception $e){
                $db->rollback();
                Log::write(implode([$e->getMessage(),"\nFILE: ", $e->getFile(), "\nLINE: ", $e->getLine(),"\nTRACE: ", $e->getTraceAsString(),"\n"]),'ERROR');
            }
            return ['success'=>false, 'message'=>'修改失败.'];
        }
    }

    /**
     * 自动绑定到全局商品字典
     */
    private function attachToGoodsDict(\sys\Db $db, array $goods) :array {
        if(null !== ($row = $db->table('tp_nb_goods')->where([['code','=', $goods['code']], ['mid','=', 0]])->find())){
            return $row;
        }

        $time = time();
        $goods['id'] = $db->table('tp_nb_goods')->insert([
            'mid'           => 0,
            'name'          => $goods['name'],
            'img'           => $goods['img'],
            'spec'          => $goods['spec'],
            'code'          => $goods['code'],
            'icode'         => intval($goods['code']),
            'suggest_price' => (float)$goods['sale_price'] ?? 0,
            'createtime'    => $time,
            'updatetime'    => $time,
            'validate'      => 0,
            'allow_ol'      => true,
            'on_sale'       => true,
        ]);

        # 保持照片不再删除
        if(!empty($goods['img'])) {
            \lib\ExtiStorage::setmeta($goods['img'], null);
        }
        return $goods;
    }


    public function match(Request $request, Response $response) : array {
        $post = json_decode($request->getContent(), true);
        validate([
            'code' => 'require|length:1,14',
        ], __FILE__.'.'.__LINE__)->check($post);

        $db = new \sys\Db();
        $result = $db->table('tp_nb_goods')->index('code',true)->where(['code','LIKE', '%'.$post['code']])
            ->field(['id', 'name','img','code','`suggest_price` AS `sale_price`'])
            ->limit(50)->select() ?? [];

        return [
            'success'=>true,
            'data'=>$result
        ];
    }
}